<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
HashMap 类，它是字典类的一种散列列表。散列算法的作用是尽可能快的在数据结构中找到一个值。
基本方法有：
1. 内部方法：将key值转换成字符串
2. 生成hashCode
3. 设置键值对
4. 获取键对应的值
5. 是否有键
6. 清空
7. 遍历键
8. 遍历值
9. 循环forEach
<script>
	{
		class ValuePair {
			constructor(key, val) {
				this.key = key
        this.value = val
			}
    }

		class HashMap {
			table = {}

			// 内部方法：将key值转换成字符串
      _toStr (key) {
				if (key === null) {
					return 'NULL'
        } else if (key === undefined) {
					return 'UNDEFINED'
        } else if (typeof key === 'string' && key instanceof String) {
					return key
        } else {
					return JSON.stringify(key)
        }
      }
			// 生成hashCode
      _hashCode (key) {
				const keyStr = this._toStr(key)
        let hash = 5381
        for (let i = 0; i < keyStr.length; i ++) {
					hash = (hash * 33) + keyStr.charCodeAt(i)
        }
				return hash % 1013
      }
			// 设置键值对
      set (key, val) {
				if (key != null && val != null) {
					this.table[this._hashCode(key)] = new ValuePair(key, val)
          return true
        }
				return false
      }
			// 获取键对应的值
      get (key) {
				if (key == null) return
        return this.table[this._hashCode(key)]?.value
      }
			// 是否有键
      has (key) {
				if (key == null) return false
				return this.table[this._hashCode(key)] != null
      }
			// 清空
      clear () {
				this.table = {}
      }
			_keyValues () {
				return Object.values(this.table)
      }
			// 遍历键
      keys () {
				return this._keyValues().map(o => o.key)
      }
			// 遍历值
      values () {
	      return this._keyValues().map(o => o.value)
      }
			// 循环forEach
      forEach (cb) {
				if (cb) {
					const kv = this._keyValues()
          for (const item of kv) {
						cb(item.key, item.value)
          }
        }
      }
    }

		const hashMap = new HashMap()
    hashMap.set('a', 'foo')
    hashMap.set('b', { name: 'b', age: 18 })
    console.log(hashMap)
		hashMap.forEach((k, v) => {
			console.log('----')
			console.log(k)
			console.log(v)
    })

  }
</script>

<body>
<script>
  class ValuePair {
    constructor(key, value) {
      this.key = key
      this.value = value
    }
  }

  class HashMap {
    table = {}

    toStr (key) {
      if (key === null) {
        return 'NULL'
      } else if (key === undefined) {
        return 'UNDEFINED'
      } else if (typeof key === 'string' && key instanceof String) {
        return key
      } else {
        return JSON.stringify(key)
      }
    }

    // 转成字符串
    // charCodeAt +
    // %
    // hashCode (key) {
    //   const keyStr = this.toStr(key)
    //   let code = 0
    //   for (let i = 0; i < keyStr.length; i ++) {
    //     code += keyStr.charCodeAt(i)
    //   }
    //   return code % 98
    // }

    hashCode (key) {
      const keyStr = this.toStr(key)
      let hash = 5381
      for (let i = 0; i < keyStr.length; i ++) {
        hash = (hash * 33) + keyStr.charCodeAt(i)
      }
      return hash % 1013
    }

    set (key, val) {
      if (key != null && val != null) {
        const position = this.hashCode(key)
        this.table[position] = new ValuePair(key, val)
        return true
      }
      return false
    }

    get (key) {
      if (key != null) {
        return this.table[this.hashCode(key)]?.value
      }
    }

    has (key) {
      if (key != null) {
        return this.table[this.hashCode(key)] != null
      }
      return false
    }

    clear () {
      this.table = {}
    }

    keys () {
      return this.keyValues().map(o => o.key)
    }

    values () {
      return this.keyValues().map(o => o.value)
    }

    keyValues () {
      return Object.values(this.table)
    }

    forEach (cb) {
      if (cb) {
        const kv = this.keyValues()
        for (let i = 0; i < kv.length; i ++) {
          cb(kv[i].key, kv[i].value)
        }
      }
    }
  }

  const hashMap = new HashMap()

  hashMap.set('a', 'aaa')
  hashMap.set('b', 'bbb')
  hashMap.set({ a: 1 }, { a: 1 })

  hashMap.forEach((k, v) => {
    console.log(k, '---k')
    console.log(v, '---v')
  })
</script>
</body>
</html>
